﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace System {
	/// <summary>
	/// List
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class PackageList<T> : PackageUnit,IList<T> {
		#region Fields
		public static readonly PackageProperty CountProperty = PackageProperty.Register("Count", typeof(Int32), typeof(PackageList<T>));
		public static readonly PackageProperty IsReadOnlyProperty = PackageProperty.Register("IsReadOnly", typeof(Boolean), typeof(PackageList<T>));
		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		private List<T> _list;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		private T[] _backup;
		#endregion
		#region Constructor
		/// <summary>
		/// Initializes a new instance of the <see cref="PackageList&lt;T&gt;"/> class.
		/// </summary>
		public PackageList() {
			_list = new List<T>();
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="PackageList&lt;T&gt;"/> class.
		/// </summary>
		/// <param name="capacity">The capacity.</param>
		public PackageList(Int32 capacity) {
			_list = new List<T>(capacity);
		}
		/// <summary>
		/// Initializes a new instance of the <see cref="PackageList&lt;T&gt;"/> class.
		/// </summary>
		/// <param name="collection">The collection.</param>
		public PackageList(IEnumerable<T> collection) {
			if (collection != null) {
				_list = new List<T>(collection);
				this.Count = _list.Count;
			} else {
				_list = new List<T>();
			}
		}
		#endregion
		#region Protected
		
		#endregion
		#region Public
		/// <summary>
		/// Returns a <see cref="System.String"/> that represents this instance.
		/// </summary>
		/// <returns>
		/// A <see cref="System.String"/> that represents this instance.
		/// </returns>
		public override string ToString() {
			return "Count = " + _list.Count.ToString();
		}

		/// <summary>
		/// Begins the edit only of this object.
		/// Use static functions to enumerate though children.
		/// </summary>
		public override void BeginEdit() {
			if (!this.IsInEdit) {
				_backup = _list.ToArray();
				if (typeof(T).IsSubclassOf(typeof(PackageUnit))) {
					foreach (T item in _list) {
						((PackageUnit)(item as Object)).BeginEdit();
					}
				}
			}
			base.BeginEdit();
		}
		/// <summary>
		/// Ends the edit only of this object.
		/// Use static functions to enumerate though children.
		/// </summary>
		public override void EndEdit() {
			if (this.IsInEdit) {
				if (typeof(T).IsSubclassOf(typeof(PackageUnit))) {
					foreach (T item in _list) {
						((PackageUnit)(item as Object)).EndEdit();
					}
				}
				_backup = null;
			}
			base.EndEdit();
		}
		/// <summary>
		/// Cancels the edit only of this object.
		/// Use static functions to enumerate though children.
		/// </summary>
		public override void CancelEdit() {
			if (this.IsInEdit) {
				if (typeof(T).IsSubclassOf(typeof(PackageUnit))) {
					foreach (T item in _list) {
						((PackageUnit)(item as Object)).CancelEdit();
					}
				}
				_list.Clear();
				_list.AddRange(_backup);
				this.Count = _list.Count;
				_backup = null;
			}
			base.CancelEdit();
		}


		/// <summary>
		/// Adds the specified item.
		/// </summary>
		/// <param name="item">The item.</param>
		public void Add(T item) {
			if (!this.IsReadOnly) {
				_list.Add(item);
				this.Count = _list.Count;
			}
		}
		/// <summary>
		/// Adds the range.
		/// </summary>
		/// <param name="collection">The collection.</param>
		public void AddRange(IEnumerable<T> collection) {
			if (!this.IsReadOnly) {
				_list.AddRange(collection);
				this.Count = _list.Count;
			}
		}
		/// <summary>
		/// Clears this instance.
		/// </summary>
		public void Clear() {
			if (!this.IsReadOnly) {
				_list.Clear();
				this.Count = _list.Count;
			}
		}
		/// <summary>
		/// Copies to.
		/// </summary>
		/// <param name="array">The array.</param>
		/// <param name="arrayIndex">Index of the array.</param>
		public void CopyTo(T[] array, int arrayIndex) {
			_list.CopyTo(array, arrayIndex);
		}
		/// <summary>
		/// Determines whether [contains] [the specified item].
		/// </summary>
		/// <param name="item">The item.</param>
		/// <returns>
		/// 	<c>true</c> if [contains] [the specified item]; otherwise, <c>false</c>.
		/// </returns>
		public bool Contains(T item) {
			return _list.Contains(item);
		}
		/// <summary>
		/// Inserts item at the specified index.
		/// </summary>
		/// <param name="index">The index.</param>
		/// <param name="item">The item.</param>
		public void Insert(int index, T item) {
			if (!this.IsReadOnly) {
				_list.Insert(index,item);
				this.Count = _list.Count;
			}
		}
		public int IndexOf(T item) {
			return _list.IndexOf(item);
		}
		public void RemoveAt(int index) {
			if (!this.IsReadOnly) {
				_list.RemoveAt(index);
				this.Count = _list.Count;
			}
		}
		public bool Remove(T item) {
			if (!this.IsReadOnly) {
				if (_list.Remove(item)) {
					this.Count = _list.Count;
					return true;
				}
			}
			return false;
		}
		public void RemoveRange(int index, int count) {
			if (!this.IsReadOnly) {
				_list.RemoveRange(index, count);
				this.Count = _list.Count;
			}
		}
		public T[] ToArray() {
			return _list.ToArray();
		}


		public new IEnumerator<T> GetEnumerator() {
			return _list.GetEnumerator();
		}
		Collections.IEnumerator Collections.IEnumerable.GetEnumerator() {
			return ((Collections.IEnumerable)_list).GetEnumerator();
		}
		#endregion
		#region Static
		public static explicit operator List<T>(PackageList<T> list){
			if (list != null) {
				return list._list;
			}
			return null;
		}
		#endregion
		#region Property
		public override bool IsInEdit {
			get {
				return base.IsInEdit;
			}
			protected set {
				base.IsInEdit = value;
				if (!value) {
					_backup = null;
				}
			}
		}
		public T this[int index] {
			get {
				return _list[index];
			}
			set {
				_list[index] = value;
			}
		}

		public bool IsReadOnly {
			get {
				return (Boolean)this.GetValue(IsReadOnlyProperty);
			}
			set {
				this.SetValue(IsReadOnlyProperty, value);
			}
		}
		/// <summary>
		/// Gets the count.
		/// </summary>
		/// <value>The count.</value>
		public int Count {
			get {
				return (Int32)this.GetValue(CountProperty);
			}
			private set {
				this.SetValue(CountProperty, value);
			}
		}
		#endregion
	}
}
